﻿//_bob.last.js
{
    //namedProp.
    (function () {

        //v.2
        var namedPropWithPropObj = function (bUsePropObject, objThis, sName, prop) {

            if (!bob.utils.isBoolean(bUsePropObject) || !bUsePropObject) {
                throw new Error('Wrong argument: bUsePropObject.');
            }
            if (bob.utils.isUndefinedOrNull(objThis)) {
                throw new Error('Argument null: objThis.');
            }
            if (bob.utils.isNullOrWhiteSpace(sName)) {
                throw new Error('Wrong argument: sName.');
            }

            var ret_val = undefined;
            if (bob.utils.isFunction(prop.get_value)) {
                objThis['get_' + sName] = prop.get_value;
            }
            else if (bob.utils.isFunction(prop.get_getter)) {
                ret_val = prop.get_getter();
            }

            if (bob.utils.isFunction(prop.set_value)) {
                objThis['set_' + sName] = prop.set_value;
            }
            else if (bob.utils.isFunction(prop.get_setter)) {
                ret_val = prop.get_setter();
            }

            return ret_val;
        };

        var namedPropWithCtorParams = function (objThis, sName, value, bReadOnly, bWriteOnly) {

            if (bob.utils.isUndefinedOrNull(objThis)) {
                throw new Error('Argument null: objThis.');
            }
            if (bob.utils.isNullOrWhiteSpace(sName)) {
                throw new Error('Wrong argument: sName.');
            }

            var prop = new bob.prop.Property(value, bReadOnly, bWriteOnly);

            return namedPropWithPropObj(true, objThis, sName, prop);
        };

        bob.ns.setNs('bob.prop', {

            //v.2
            namedProp: bob.fn.overloadFunction([
                {
                    condition: function (bUsePropObject) {
                        return bob.utils.isBoolean(bUsePropObject) && bUsePropObject;
                    },
                    overload: namedPropWithPropObj
                },
                {
                    condition: function () {
                        return true;
                    },
                    overload: namedPropWithCtorParams
                }
            ])

        });

    })();

}

{
    //propFunction.
    (function () {

        //v.2
        var propFunctionWithPropObj = function (bUsePropObject, prop, bNoError) {

            if (!bob.utils.isBoolean(bUsePropObject) || !bUsePropObject) {
                throw new Error('Wrong argument: bUsePropObject.');
            }
            if (bob.utils.isUndefinedOrNull(prop)) {
                throw new Error('Argument null: prop.');
            }

            var fn = function () {
                if (!arguments.length) {
                    if (bob.utils.isFunction(prop.get_value)) {
                        return prop.get_value();
                    }
                    else if (!bNoError) {
                        throw new Error('Cannot get value of write-only property.');
                    }
                }
                else {
                    if (bob.utils.isFunction(prop.set_value)) {
                        prop.set_value(arguments[0]);
                    }
                    else if (!bNoError) {
                        throw new Error('Cannot set value of read-only property.');
                    }
                }
            };
            return fn;
        };

        //v.2
        var propFunctionWithCtorParams = function (bUsePropObject, value, bReadOnly, bWriteOnly, bNoError) {

            if (!bob.utils.isBoolean(bUsePropObject) || bUsePropObject) {
                throw new Error('Wrong argument: bUsePropObject.');
            }

            var prop = new bob.prop.Property(value, bReadOnly, bWriteOnly);

            return propFunctionWithPropObj(true, prop, bNoError);
        };

        bob.ns.setNs('bob.prop', {

            //v.2
            propFunction: bob.fn.overloadFunction([
                {
                    condition: function (bUsePropObject) {
                        return bUsePropObject ? true : false;
                    },
                    overload: propFunctionWithPropObj
                },
                {
                    condition: function () {
                        return true;
                    },
                    overload: propFunctionWithCtorParams
                }
            ])

        });
    })();
}

{

    //namedPropFunction
    (function () {

        //v.2
        var namedPropFnWithPropObj = function (bUsePropObject, objThis, sName, propObject, bNoError) {
            if (bob.utils.isUndefinedOrNull(objThis)) {
                throw new Error('Argument null: objThis.');
            }
            if (bob.utils.isNullOrWhiteSpace(sName)) {
                throw new Error('Wrong argument: sName.');
            }

            var prop = propObject;
            objThis[sName] = bob.prop.propFunction(true, prop, bNoError);

            var ret_val = undefined;
            if (bob.utils.isFunction(prop.get_getter)) {
                ret_val = prop.get_getter();
            }
            else if (bob.utils.isFunction(prop.get_setter)) {
                ret_val = prop.get_setter();
            }

            return ret_val;
        };

        var namedPropFnWithPropParams = function (objThis, sName, value, bReadOnly, bWriteOnly, bNoError) {
            if (bob.utils.isUndefinedOrNull(objThis)) {
                throw new Error('Argument null: objThis.');
            }
            if (bob.utils.isNullOrWhiteSpace(sName)) {
                throw new Error('Wrong argument: sName.');
            }

            var prop = new bob.prop.Property(value, bReadOnly, bWriteOnly);
            return namedPropFnWithPropObj(true, objThis, sName, prop, bNoError);
        };

        bob.ns.setNs('bob.prop', {

            //v.2
            namedPropFunction: bob.fn.overloadFunction([
                {
                    condition: function (bUsePropObject) {
                        return bob.utils.isBoolean(bUsePropObject) && bUsePropObject;
                    },
                    overload: namedPropFnWithPropObj
                },
                {
                    condition: function () {
                        return true;
                    },
                    overload: namedPropFnWithPropParams
                }
            ])

        });

    })();
 
}

{
    //clone.
    (function () {

        //v.2
        var cloneWithConditionFn = function (fnIndexCondition, objDestination) {
            var obj = this;

            if (bob.utils.isUndefinedOrNull(fnIndexCondition)) {
                fnIndexCondition = function () { return true; };
            }
            else if (!bob.utils.isFunction(fnIndexCondition)) {
                throw new Error('Wrong argument: fnIndexCondition.');
            }

            var resCreator = bob.collections.getCollectionCreator(obj, objDestination);
            bob.collections.extensions.forEach.call(obj, function (index, item) {
                if (fnIndexCondition.call(item, index, item)) {
                    resCreator.addItem(index, item);
                }
            });

            return resCreator.getValue();
        };

        var cloneWithIndexes = function (iFrom, iTo, arrDestination) {
            var array = this;

            if (!bob.utils.isArray(array)) {
                throw new Error('Wrong context: Array expected.');
            }

            var result = bob.utils.ifUndefinedOrNull(arrDestination, []);
            var startIndex = bob.utils.ifUndefinedOrNull(iFrom, 0);
            var endIndex = bob.utils.ifUndefinedOrNull(iTo, array.length - 1);
            cloneWithConditionFn.call(array, function (index, item) {
                return (index >= startIndex) && (index <= endIndex);
            }, result);

            return result;
        };

        bob.ns.setNs('bob.collections.extensions', {
            //v.2
            clone: bob.fn.overloadFunction([
                {
                    condition: function (iFrom, iTo, arrDestination) {
                        return (bob.utils.isArray(this))
                            && (bob.utils.isUndefinedOrNull(iFrom) || bob.utils.isNumber(iFrom))
                            && (bob.utils.isUndefinedOrNull(iTo) || bob.utils.isNumber(iTo))
                            && (bob.utils.isUndefinedOrNull(arrDestination) || bob.utils.isArray(arrDestination));
                    },
                    overload: cloneWithIndexes
                },
                {
                    condition: function () {
                        return true;
                    },
                    overload: cloneWithConditionFn
                }
            ])
        });

    })();

}

{ 
    //except.
    (function () {

        var except_withFn = function (fnCondition) {
            var array = this;

            if (!bob.utils.isFunction(fnCondition)) {
                throw new Error('Wrong argument: fnCondition.');
            }

            var resCreator = bob.collections.getCollectionCreator(array);
            bob.collections.extensions.forEach.call(array, function (index, item) {
                if (!fnCondition.call(item, index, item)) {
                    resCreator.addItem(index, item);
                }
            });

            return resCreator.getValue();
        };

        var except_withIndex = function (indexToRemove) {
            var array = this;

            var fnCondition = function (index, item) {
                return bob.utils.equals(index, indexToRemove);
            };
            return except_withFn.call(array, fnCondition);
        };

        //v3.
        var except_withItem = function (bUseItem, objItem) {
            var array = this;
            var fnCondition = function (index, item) {
                return bob.utils.equals(item, objItem);
            };
            return except_withFn.call(array, fnCondition);
        };

        bob.ns.setNs('bob.collections.extensions', {

            except: bob.fn.overloadFunction([
                {
                    condition: function (fnCondition) {
                        return bob.utils.isFunction(fnCondition);
                    },
                    overload: except_withFn
                },
                {
                    condition: function (bUseItem) {
                        return bob.utils.isBoolean(bUseItem);
                    },
                    overload: except_withItem
                },
                {
                    condition: function () {
                        return true;
                    },
                    overload: except_withIndex
                }
            ])

        });

    })();
}

{
    //fixedObjectFunction.
    (function () {

        //v.2
        var fixedObjFunc_withFn = function (objSource, func) {
            if (bob.utils.isUndefinedOrNull(objSource)) {
                throw new Error('Wrong argument: objSource.');
            }
            if (!bob.utils.isFunction(func)) {
                throw new Error('Wrong argument: func.');
            }

            return function () {
                return func.apply(objSource, arguments);
            };
        };

        //v.2
        var fixedObjFunc_withStr = function (objSource, fnName) {
            if (bob.utils.isUndefinedOrNull(objSource)) {
                throw new Error('Wrong argument: objSource.');
            }
            if (!bob.utils.isString(fnName) || bob.utils.isNullOrWhiteSpace(fnName)) {
                throw new Error('Wrong argument: fnName.');
            }

            var func = objSource[fnName];
            if (!bob.utils.isFunction(func)) {
                throw new Error(bob.string.formatString('Cannot find function "{0}".', fnName));
            }

            return fixedObjFunc_withFn(objSource, func);
        };

        bob.ns.setNs('bob.fn', {

            //v.2
            fixedObjectFunction: bob.fn.overloadFunction([
                { overload: fixedObjFunc_withFn, condition: function (objSource, func) { return bob.utils.isFunction(func); } },
                { overload: fixedObjFunc_withStr, condition: function () { return true; } }
                
            ])

        });
    })();
}

{
    //namedEvent
    (function () {

        var namedEvent_withName = function (objThis, sName) {
            if (bob.utils.isUndefinedOrNull(objThis)) {
                throw new Error('Argument null: objThis.');
            }
            if (bob.utils.isNullOrWhiteSpace(sName)) {
                throw new Error('Wrong argument: sName.');
            }

            var evt = new bob.event.Event();

            return namedEvent_withEventObj(true, objThis, sName, evt);
        };

        //v3
        var namedEvent_withEventObj = function (bUseEventObj, objThis, sName, eventObj) {
            if (!bob.utils.isBoolean(bUseEventObj) || !bUseEventObj) {
                throw new Error('Wrong argument: bUseEventObj.');
            }
            if (bob.utils.isUndefinedOrNull(objThis)) {
                throw new Error('Argument null: objThis.');
            }
            if (bob.utils.isNullOrWhiteSpace(sName)) {
                throw new Error('Wrong argument: sName.');
            }
            if (bob.utils.isUndefinedOrNull(eventObj)) {
                throw new Error('Argument null: eventObj.');
            }

            objThis['add_' + sName] = eventObj.add_handler;
            objThis['remove_' + sName] = eventObj.remove_handler;

            var ret_val = undefined;
            if (bob.utils.isFunction(eventObj.get_caller)) {
                ret_val = eventObj.get_caller();
            }

            return ret_val;
        };

        bob.ns.setNs('bob.event', {

            namedEvent: bob.fn.overloadFunction([
                {
                    //v3
                    overload: namedEvent_withEventObj,
                    condition: function (bUseEventObj) {
                        return bob.utils.isBoolean(bUseEventObj) && bUseEventObj;
                    }
                },
                {
                    overload: namedEvent_withName,
                    condition: function () { return true; }
                }
            ])

        });

    })();
}

{
    //setLoaded, whenLoaded.
    (function () {

        var _moduleObserver = new bob.code.module.ModuleObserver();

        var _ns = {

            //v.2
            setLoaded: function () { },

            //v.2
            whenLoaded: function () { }
        };
        
        _ns = bob.obj.extractInterface(_moduleObserver, _ns);

        bob.ns.setNs('bob.code.module', _ns);

    })();
}

{
    //indexOf
    (function () {

        //v3
        var indexOf_withCriteria = function (fnCriteria) {
            var arr = this;

            if (!bob.utils.isFunction(fnCriteria)) {
                throw new Error('Wrong argument: fnCriteria.');
            }

            var resultIndex = undefined;
            var fnAny = function (index, item) {
                var match = fnCriteria.call(item, index, item);
                if (match) {
                    resultIndex = index;
                }
                return match;
            };
            bob.collections.extensions.any.call(arr, fnAny);

            return resultIndex;
        };

        //v3
        var indexOf_withItem = function (bUseItem, objItem) {
            var arr = this;

            var fnCriteria = function (index, item) {
                return bob.utils.equals(objItem, item);
            };

            return indexOf_withCriteria.call(arr, fnCriteria);
        };

        bob.ns.setNs('bob.collections.extensions', {

            indexOf: bob.fn.overloadFunction([
                {
                    overload: indexOf_withItem,
                    condition: function (bUseItem, objItem) {
                        return arguments.length == 2 && bob.utils.isBoolean(bUseItem);
                    }
                },
                {
                    overload: indexOf_withCriteria,
                    condition: function () { return true; }
                }
            ])

        });

    })();
}

